package com.ruoyi.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.system.domain.vo.WxConfig;
import com.ruoyi.system.service.IWxService;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

@Service
public class WxServiceImpl implements IWxService {

    private static final Logger logger = LoggerFactory.getLogger(WxServiceImpl.class);

    public static final String STR = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890";
    private static final String ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

    public static final String TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi";

    @Value("${wx.app_id}")
    private String appId;
    @Value("${wx.app_secret}")
    private String appSecret;
    @Value("${wx.host}")
    private String host;
    @Autowired
    private RedisTemplate redisTemplate;

    private String getAccessToken() {
        String url = String.format(ACCESS_TOKEN, appId, appSecret);
        String s = HttpUtils.sendGet(url);
        JSONObject jsonObject = JSON.parseObject(s);
        return jsonObject.getString("access_token");
    }

    private String getTicket() {
        String ticket = (String) redisTemplate.opsForValue().get("ticket");
        if (StringUtils.isEmpty(ticket)) {
            String accessToken = getAccessToken();
            String url = String.format(TICKET, accessToken);
            String s = HttpUtils.sendGet(url);
            JSONObject jsonObject = JSON.parseObject(s);
            ticket = jsonObject.getString("ticket");
            redisTemplate.opsForValue().set("ticket", ticket, 3000, TimeUnit.SECONDS);
            return ticket;
        }
        return ticket;
    }

    @Override
    public WxConfig getWxSigned(Map<String, Object> map) {

        StringBuilder stringBuilder = new StringBuilder();
        map.keySet().forEach(item -> stringBuilder.append(item).append("=").append(map.get(item)).append("&"));
        String param = StringUtils.removeEnd(stringBuilder.toString(), "&");
        String ticket = getTicket();
        String random = randomText(10);
        long l = DateUtils.getNowDate().getTime() / 1000;
        String fullSignStr = "jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s";
        String pathInfo = host + "/?" + param;
        String signed = String.format(fullSignStr, ticket, random, l, pathInfo);
        try {
            logger.info("signed: {}", signed);
            WxConfig wxConfig = new WxConfig();
            wxConfig.setAppId(appId);
            wxConfig.setNonceStr(random);
            wxConfig.setSignature(sha1(signed));
            wxConfig.setTimestamp(l);

            List<String> list = new ArrayList<>();
            list.add("updateAppMessageShareData");
            list.add("updateTimelineShareData");
            list.add("onMenuShareWeibo");
            list.add("onMenuShareQZone");
            wxConfig.setJsApiList(list);

            return wxConfig;
        } catch (Exception e) {
            logger.error("微信获取失败", e);
        }
        return null;
    }

    private String sha1(String plainText) throws NoSuchAlgorithmException {
        // 获取指定摘要算法的messageDigest对象
        MessageDigest messageDigest = MessageDigest.getInstance("SHA"); // 此处的sha代表sha1
        // 调用digest方法，进行加密操作
        byte[] cipherBytes = messageDigest.digest(plainText.getBytes());
        return Hex.encodeHexString(cipherBytes);
    }

    private String randomText(int count) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < count; i++) {
            int num = RandomUtils.nextInt(0, 60);
            stringBuilder.append(STR.charAt(num));
        }
        return stringBuilder.toString();
    }
}
